#region Released to Public Domain by Gael Fraiteur
/*----------------------------------------------------------------------------*
 *   This file is part of samples of PostSharp.                                *
 *                                                                             *
 *   This sample is free software: you have an unlimited right to              *
 *   redistribute it and/or modify it.                                         *
 *                                                                             *
 *   This sample is distributed in the hope that it will be useful,            *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                      *
 *                                                                             *
 *----------------------------------------------------------------------------*/
#endregion

using System;

namespace PostSharp.Samples.Librarian.Framework
{
    /// <summary>
    /// Base of classes whose implementation can be completed
    /// at post-compilation time by code generation.
    /// </summary>
    [Serializable]
    public abstract class Aspectable : ICloneable, IValidable
    {
        #region ICloneable Members

        /// <summary>
        /// Creates a deep clone of the current object.
        /// </summary>
        /// <returns>A deep clone of the current object.</returns>
        object ICloneable.Clone()
        {
            return this.Clone();
        }

        /// <summary>
        /// Creates a deep clone of the current object.
        /// </summary>
        /// <returns>A deep clone of the current object.</returns>
        /// <remarks>
        /// The default implementation of this method is to create a shallow copy of
        /// the current object, then to call the <see cref="CopyTo"/> method.
        /// Derived classes are expected to implement this method so that it
        /// clones all members that need to be cloned (that is, all reference types
        /// expected <see cref="string"/>.). The <see cref="CopyTo"/> method
        /// is generated automatically at compile time.
        /// </remarks>
        public virtual Aspectable Clone()
        {
            // Create a shallow copy of the current object.
            Aspectable clone =
                (Aspectable) this.MemberwiseClone();

            // Copy the members that require to be cloned.
            this.CopyTo( clone );

            return clone;
        }

        /// <summary>
        /// Copy, into another object of the same type as the current one,
        /// all cloneable members.
        /// </summary>
        /// <param name="clone">Target objects.</param>
        /// <remarks>
        /// This method is implemented automatically at post-compile time
        /// in derived classes.
        /// </remarks>
        protected virtual void CopyTo( Aspectable clone )
        {
        }

        #endregion

        #region IValidable Members

        /// <summary>
        /// Validates the fields having a validation custom attribute (<see cref="FieldValidationAttribute"/>).
        /// </summary>
        /// <remarks>
        /// This method is implemented automatically at post-compile time
        /// in derived classes.
        /// </remarks>
        protected virtual void AutoGeneratedValidate()
        {
        }

        /// <summary>
        /// Validates the current method (throws the <see cref="ValidationException"/> instead of error).
        /// </summary>
        /// <remarks>
        /// The default implementation of this method is to validate the fields having a validation
        /// custom attribute. If further validation is required (for instance validation rules involving
        /// more than a single field), derived class may override this method, but should call
        /// the base method.
        /// </remarks>
        public virtual void Validate()
        {
            this.AutoGeneratedValidate();
        }

        #endregion
    }
}